import logging
import jsonpickle
import model.strutils as strutils

FORMAT = "%(message)s - %(filename)s %(lineno)d "
logging.basicConfig(level=logging.INFO, 
                    format=FORMAT, 
#                    filename='app.log'
                    )
#console = logging.StreamHandler()
#console.setLevel(logging.INFO)
## set a format which is simpler for console use
#formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
## tell the handler to use this format
#console.setFormatter(formatter)
## add the handler to the root logger
#logging.getLogger().addHandler(console)
#
#logging.warn("ready")

import tornado.httpserver
import tornado.ioloop
import tornado.web
import websocket
import simplejson as json
from optparse import OptionParser
import GameServerCallbacks
from GameServerCallbacks import ClientMethod
from collections import defaultdict
import random

from datastore.GameContextDataStore import GameContextDataStore



handler_map = {
               "update_thief":GameServerCallbacks.update_thief,
               "join_game":GameServerCallbacks.join_game,
               "send_message":GameServerCallbacks.send_message,
               "register":GameServerCallbacks.register,
               "end_turn":GameServerCallbacks.end_turn, 
               "start_game":GameServerCallbacks.start_game,  
               "init_settlement":GameServerCallbacks.init_settlement, 
               "init_road":GameServerCallbacks.init_road, 
               "buy_settlement":GameServerCallbacks.buy_settlement, 
               "buy_road":GameServerCallbacks.buy_road, 
               "upgrade_settlement":GameServerCallbacks.upgrade_settlement, 
               "host_game":GameServerCallbacks.host_game,
               "get_game_list":GameServerCallbacks.get_game_list,
               "init_settlement":GameServerCallbacks.init_settlement,
               "init_road":GameServerCallbacks.init_road,
               "end_turn":GameServerCallbacks.end_turn,
               }


def broadcast(ress):
  for res in ress:
    if(res.has_key("1")):
      jsonpickle.encode(res["1"])
#      logging.error('to msg %s' % jsonpickle.encode(res["1"]))
#    logging.error('to msg %s' % (json.dumps(res.items()[0]["1"])))

def on_message(message):
  logging.info("request %s" % message)
  fun_call = json.loads(message.encode('ascii','ignore'))
  res = handler_map[fun_call['type']](**fun_call['data'])
  logging.info("res %s" % strutils.sm_res(res))
  broadcast(res)
  return res
       
class ApplicationServer():
  def __init__(self):
    self.player_socket_map = {}
  
  def add_socket(self, token, socket):
    logging.warning('add socket for token %s' % token)
    self.player_socket_map[token] = socket

  def broadcast_all(self, msg):
    logging.warning('broadcasting %s' % msg)
    for token, socket in self.player_socket_map.items():
      socket.write_message(str(msg))
    
  def broadcast(self, *responses):
    for res in responses:
      for token in res.keys():
        logging.warning('to token %s, msg %s' % (token, str(res[token])))
        if token in self.player_socket_map:
          self.player_socket_map[token].write_message(jsonpickle.encode(res[token]))
        else:
          logging.warning('token %s has no socket' % token)
        
class EchoWebSocket(websocket.WebSocketHandler):
  def __init__(self, *args, **kwargs):
    global server
    self.server = server
    super(EchoWebSocket, self).__init__(*args, **kwargs)
  
  def open(self):
    logging.warning('new connetion')
    self.receive_message(self.on_message)

  def on_message(self, message):
    logging.info("request %s" % message)
    
#    res = random.randint(1,10)
    if "broadcast" in message:
      server.broadcast_all(message)
    else:
      fun_call = json.loads(message.encode('ascii','ignore'))
      res = handler_map[fun_call['type']](**fun_call['data'])
      logging.info("res %s" % strutils.sm_res(res))
      if "register" in message and res:
        #Sorry about the hack
        server.add_socket(res[0].items()[0][0], self)
      server.broadcast(*res)
    self.receive_message(self.on_message)
    
  def on_connection_close(self):
    logging.warning('connection closed from browser.. ending game')
    removed_player_tokens = []
    if self in server.player_socket_map.values():
      for player_token in server.player_socket_map.keys():
        if server.player_socket_map[player_token] == self:
          logging.warning("removing socket for player %s" % player_token)
          del server.player_socket_map[player_token]
          removed_player_tokens.append(player_token)
    for player_token in removed_player_tokens:
      res = GameServerCallbacks.end_games_with_player(player_token)
      server.broadcast(*res)


def test_main():
  def single_player_game():
    token1 = on_message('{"type":"register", "data":{}}')
    on_message('{"type":"host_game", "data":{"token":"1"}}')
    on_message('{"type":"start_game", "data":{"token":"1", "game_id":0}}')
    on_message('{"type":"init_settlement", "data":{"token":"1", "game_id":0, "vertex_id":40}}')
    on_message('{"type":"end_turn", "data":{"token":"1", "game_id":0}}')
    on_message('{"type":"init_settlement", "data":{"token":"1", "game_id":0, "vertex_id":44}}')
    on_message('{"type":"end_turn", "data":{"token":"1", "game_id":0, "dice":[1,1]}}')
    on_message('{"type":"end_turn", "data":{"token":"1", "game_id":0, "dice":[1,1]}}')
    on_message('{"type":"end_turn", "data":{"token":"1", "game_id":0, "dice":[1,1]}}')
    on_message('{"type":"update_thief", "data":{"token":"1", "game_id":0, "hex_id":17}}')
    on_message('{"type":"end_turn", "data":{"token":"1", "game_id":0, "dice":[1,1]}}')
    on_message('{"type":"init_settlement", "data":{"token":"1", "game_id":0, "vertex_id":45}}')
    on_message('{"type":"end_turn", "data":{"token":"1", "game_id":0, "dice":[1,1]}}')
    on_message('{"type":"upgrade_settlement", "data":{"token":"1", "game_id":0, "vertex_id":45}}')
  
  def multi_player_game():
    token2 = on_message('{"type":"register", "data":{}}')
    on_message('{"type":"host_game", "data":{"token":"1"}}')
    token3 = on_message('{"type":"register", "data":{}}')
    #on_message('{"type":"get_game_list", "data":{}}')
    on_message('{"type":"join_game", "data":{"token":"2", "game_id":0}}')
    on_message('{"type":"join_game", "data":{"token":"3", "game_id":0}}')
    
    # GameState WAITING_FOR_START -> INIT1
    on_message('{"type":"start_game", "data":{"token":"3", "game_id":0}}')
    on_message('{"type":"init_settlement", "data":{"token":"1", "game_id":0, "vertex_id":0}}')
    on_message('{"type":"init_road", "data":{"token":"1", "game_id":0, "edge_id":0}}')
    on_message('{"type":"end_turn", "data":{"token":"1", "game_id":0}}')
    on_message('{"type":"init_settlement", "data":{"token":"2", "game_id":0, "vertex_id":1}}')
    on_message('{"type":"init_road", "data":{"token":"2", "game_id":0, "edge_id":1}}')
    on_message('{"type":"end_turn", "data":{"token":"2", "game_id":0}}')
    on_message('{"type":"init_settlement", "data":{"token":"3", "game_id":0, "vertex_id":2}}')
    on_message('{"type":"init_road", "data":{"token":"3", "game_id":0, "edge_id":2}}')
    on_message('{"type":"end_turn", "data":{"token":"3", "game_id":0}}')
    # GameState INIT1 -> INIT2
    on_message('{"type":"init_settlement", "data":{"token":"3", "game_id":0, "vertex_id":3}}')
    on_message('{"type":"init_road", "data":{"token":"3", "game_id":0, "edge_id":3}}')
    on_message('{"type":"end_turn", "data":{"token":"3", "game_id":0}}')
    on_message('{"type":"init_settlement", "data":{"token":"2", "game_id":0, "vertex_id":4}}')
    on_message('{"type":"init_road", "data":{"token":"2", "game_id":0, "edge_id":4}}')
    on_message('{"type":"end_turn", "data":{"token":"2", "game_id":0}}')
    on_message('{"type":"init_settlement", "data":{"token":"1", "game_id":0, "vertex_id":5}}')
    on_message('{"type":"init_road", "data":{"token":"1", "game_id":0, "edge_id":5}}')
    on_message('{"type":"end_turn", "data":{"token":"1", "game_id":0}}')
    # GameState INIT2 -> PLAYING_GAME
    on_message('{"type":"buy_settlement", "data":{"token":"1", "game_id":0, "vertex_id":6}}')
    on_message('{"type":"buy_road", "data":{"token":"1", "game_id":0, "edge_id":6}}')
    on_message('{"type":"end_turn", "data":{"token":"1", "game_id":0}}')
    on_message('{"type":"buy_settlement", "data":{"token":"2", "game_id":0, "vertex_id":6}}')
    on_message('{"type":"buy_road", "data":{"token":"2", "game_id":0, "edge_id":6}}')
    on_message('{"type":"end_turn", "data":{"token":"2", "game_id":0}}')
    on_message('{"type":"end_turn", "data":{"token":"3", "game_id":0}}')
    on_message('{"type":"upgrade_settlement", "data":{"token":"1", "game_id":0, "vertex_id":6}}')
    on_message('{"type":"end_turn", "data":{"token":"1", "game_id":0}}')
    
  #multi_player_game()
  single_player_game()  
  
#  token2 = on_message('{"type":"register", "data":{}}')
#  token3 = on_message('{"type":"register", "data":{}}')
#  #on_message('{"type":"get_game_list", "data":{}}')
#  on_message('{"type":"join_game", "data":{"token":"2", "game_id":0}}')
#  on_message('{"type":"join_game", "data":{"token":"3", "game_id":0}}')
#  # GameState WAITING_FOR_START -> INIT1
#  on_message('{"type":"start_game", "data":{"token":"3", "game_id":0}}')
#  on_message('{"type":"init_settlement", "data":{"token":"1", "game_id":0, "vertex_id":0}}')
#  on_message('{"type":"init_road", "data":{"token":"1", "game_id":0, "edge_id":0}}')
#  on_message('{"type":"end_turn", "data":{"token":"1", "game_id":0}}')
#  on_message('{"type":"init_settlement", "data":{"token":"2", "game_id":0, "vertex_id":1}}')
#  on_message('{"type":"init_road", "data":{"token":"2", "game_id":0, "edge_id":1}}')
#  on_message('{"type":"end_turn", "data":{"token":"2", "game_id":0}}')
#  on_message('{"type":"init_settlement", "data":{"token":"3", "game_id":0, "vertex_id":2}}')
#  on_message('{"type":"init_road", "data":{"token":"3", "game_id":0, "edge_id":2}}')
#  on_message('{"type":"end_turn", "data":{"token":"3", "game_id":0}}')
#  # GameState INIT1 -> INIT2
#  on_message('{"type":"init_settlement", "data":{"token":"3", "game_id":0, "vertex_id":3}}')
#  on_message('{"type":"init_road", "data":{"token":"3", "game_id":0, "edge_id":3}}')
#  on_message('{"type":"end_turn", "data":{"token":"3", "game_id":0}}')
#  on_message('{"type":"init_settlement", "data":{"token":"2", "game_id":0, "vertex_id":4}}')
#  on_message('{"type":"init_road", "data":{"token":"2", "game_id":0, "edge_id":4}}')
#  on_message('{"type":"end_turn", "data":{"token":"2", "game_id":0}}')
#  on_message('{"type":"init_settlement", "data":{"token":"1", "game_id":0, "vertex_id":5}}')
#  on_message('{"type":"init_road", "data":{"token":"1", "game_id":0, "edge_id":5}}')
#  on_message('{"type":"end_turn", "data":{"token":"1", "game_id":0}}')
#  # GameState INIT2 -> PLAYING_GAME
#  on_message('{"type":"buy_settlement", "data":{"token":"1", "game_id":0, "vertex_id":6}}')
#  on_message('{"type":"buy_road", "data":{"token":"1", "game_id":0, "edge_id":6}}')
#  on_message('{"type":"end_turn", "data":{"token":"1", "game_id":0}}')
#  on_message('{"type":"buy_settlement", "data":{"token":"2", "game_id":0, "vertex_id":6}}')
#  on_message('{"type":"buy_road", "data":{"token":"2", "game_id":0, "edge_id":6}}')
#  on_message('{"type":"end_turn", "data":{"token":"2", "game_id":0}}')

server = ApplicationServer()
application = tornado.web.Application([
  (r'/game', EchoWebSocket),
])

def server_main():
  port = 1337
  http_server = tornado.httpserver.HTTPServer(application)
  http_server.listen(port)
  logging.warning("Starting server on port: %d" % port)
  tornado.ioloop.IOLoop.instance().start()

if __name__ == '__main__':
  parser = OptionParser()
  parser = OptionParser(usage="usage: %prog [options]")
  parser.add_option("-t", "--test",
                    action="store_true",
                    default=False,
                    help="Run the server in test mode")
  (options, args) = parser.parse_args()
  
  if options.test:
    test_main()
  else:
    server_main()




